package com.seo.textgen.pos;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.alex.utils.common.Random;
import com.seo.textgen.pos.keyword.TaggedKeyword;
import com.seo.textgen.pos.keyword.TaggedKeywordSelector;

public class PosAwareKeywordInjector {

	private int keywordDensity;

	private TaggedKeywordSelector keywordSelector;

	public PosAwareKeywordInjector(TaggedKeywordSelector keywordSelector, int keywordDensity) {
		this.keywordSelector = keywordSelector;
		this.keywordDensity = keywordDensity;
	}

	public void injectKeywords(Deque<GeneratedSentence> sentences, int wordCount) {
		TaggedKeyword[] keywords = keywordSelector.selectKeywords();
		int keywordCount = wordCount * keywordDensity / 1000;
		if (keywordCount == 0) {
			keywordCount = 1;
		}

		Map<String, LinkedList<PlaceHolder>> availablePlaceHolders = new HashMap<String, LinkedList<PlaceHolder>>();
		for (GeneratedSentence sentence : sentences) {
			for (PlaceHolder placeHolder : sentence.getPlaceHolders()) {
				LinkedList<PlaceHolder> availablePlaceHoldersForTag = availablePlaceHolders.get(placeHolder.getToken().getTag());
				if (availablePlaceHoldersForTag == null) {
					availablePlaceHoldersForTag = new LinkedList<PlaceHolder>();
					availablePlaceHolders.put(placeHolder.getToken().getTag(), availablePlaceHoldersForTag);
				}
				availablePlaceHoldersForTag.add(placeHolder);
			}
		}

		Set<Integer> keywordSentenceSet = new HashSet<Integer>();

		List<TaggedKeyword> keywordsToInject = new LinkedList<TaggedKeyword>();
		for (int i = 0; i < keywordCount; i++) {
			for (TaggedKeyword keyword : keywords) {
				keywordsToInject.add(keyword);
			}
		}
		Collections.shuffle(keywordsToInject, Random.getRandom());

		if (!keywordsToInject.isEmpty()) {
			tryInjectByTag(keywordsToInject, availablePlaceHolders, keywordSentenceSet, 0);
			if (!keywordsToInject.isEmpty()) {
				tryInjectByTag(keywordsToInject, availablePlaceHolders, keywordSentenceSet, 1);
			}
		}
		
		if (!keywordsToInject.isEmpty()) {
			List<Object> parts = new ArrayList<Object>(keywordsToInject.size() * 2);
			for (TaggedKeyword keyword : keywordsToInject) {
				if (parts.isEmpty()) {
					parts.add(StringUtils.capitalize(keyword.getKeyword()));
				} else {
					parts.add(", ");
					parts.add(keyword.getKeyword());
				}
			}
			parts.add(".");
			sentences.addFirst(new GeneratedSentence(null, parts, null));
		}
	}

	private void tryInjectByTag(List<TaggedKeyword> keywordsToInject, Map<String, LinkedList<PlaceHolder>> availablePlaceHolders,
			Set<Integer> keywordSentenceSet, int tokenNumber) {
		Iterator<TaggedKeyword> iterator = keywordsToInject.iterator();
		while (iterator.hasNext()) {
			TaggedKeyword keyword = iterator.next();
			if (keyword.getTokens().size() > tokenNumber) {
				String tag = keyword.getTokens().get(tokenNumber).getTag();
				LinkedList<PlaceHolder> placeHolders = availablePlaceHolders.get(tag);
				if (placeHolders != null && !placeHolders.isEmpty()) {
					Iterator<PlaceHolder> placeHolderIterator = placeHolders.iterator();
					while (placeHolderIterator.hasNext()) {
						PlaceHolder placeHolder = placeHolderIterator.next();
						int hash = placeHolder.getSentence().hashCode() + keyword.hashCode();
						if (keywordSentenceSet.add(hash)) {
							placeHolder.setValue(keyword.getKeyword());
							placeHolderIterator.remove();
							iterator.remove();
							break;
						}
					}
				}
			}
		}
	}

}
